package nway_fs_ctl

import (
	"errors"

	_ "log"
	_ "nway_dsr/nway_dsr/utils/conf"
	"nway_dsr/nway_dsr/utils/eventsocket"
	"nway_dsr/nway_dsr/utils/log"
	"nway_dsr/nway_dsr/utils/nway_path"
	"os"
	"time"

	"sync"

	"nway_dsr/nway_dsr/nway_fs_db"

	"github.com/astaxie/beego/config"
)

var global_c *eventsocket.Connection
var brunning bool
var event_direction bool = true
var workResultLock sync.WaitGroup
var Channels int = 1
var AnswerChannels int = 1
var UseInterface bool = false
var UseIVR bool = false
var UseAutoRoute bool = false
var CalloutRingPath string = "/user/local/freeswitch/rings"
var CalloutMustRecord string = "true"
var CalloutRecordPath string = "/user/local/freeswitch/recordings"
var RecordExt string = ".wav"
var MaxSeatNum int = 3000
var LocalIp string = "http://127.0.0.1/"
var CalloutQueueWaitTime int = 100
var UseLastTime bool = false
var ASR string
var APPID string

func GetGlobalConn() *eventsocket.Connection {
	return global_c
}
func Reconnect() (*eventsocket.Connection, error) {
	var c *eventsocket.Connection
	conf_file := nway_path.GetCurrentDirectory() + "Nway.conf"
	iniconf, errc := config.NewConfig("ini", conf_file)
	//var result int64
	if errc != nil {
		//log.Fatal(errc)
		logger.Error("config file fatal,", errc)
		return c, errc
	}
	///brunning = true
	//logger.Debug("Now to run Nway.com.cn FreeSWITCH interface service")
	ipstring := iniconf.String("fsip")
	auth := iniconf.String("auth")
	var err error
	var i int = 0
	for i < 5 {
		i = i + 1
		c, err = eventsocket.Dial(ipstring, auth)

		if err != nil {
			logger.Error("Dial to FreeSWITCH Server Failed：", err)
			//logger.Debug("Dial to FreeSWITCH Server Failed：", err)
			time.Sleep(time.Duration(5) * time.Second)
			continue
		} else {
			return c, nil
		}
		//if i == 5 {
		//	os.Exit(0)
		//}
	}
	logger.Error("Can't Connect to FS")
	return c, errors.New("Can't Connect to FS")

}
func AutoCheckConnect(cc *eventsocket.Connection) {
	var c *eventsocket.Connection
	conf_file := nway_path.GetCurrentDirectory() + "Nway.conf"
	iniconf, errc := config.NewConfig("ini", conf_file)
	//var result int64
	if errc != nil {
		//log.Fatal(errc)
		logger.Error("config file fatal,", errc)
		//return c, errc
	}
	///brunning = true
	//logger.Debug("Now to run Nway.com.cn FreeSWITCH interface service")
	ipstring := iniconf.String("fsip")
	auth := iniconf.String("auth")
	var err error
	for {
		time.Sleep(time.Duration(3) * time.Second)
		c, err = eventsocket.Dial(ipstring, auth)
		if err != nil {
			logger.Error("AutoCheckConnect Dial to FreeSWITCH Server Failed：", err)
			//logger.Debug("Dial to FreeSWITCH Server Failed：", err)

			c, err = Reconnect()
			if err == nil {
				cc = c
				cc.Send("events PLAIN ALL")
				//return
			}
		} else {
			c.Close()
			//return c, nil
		}
		//if i == 5 {
		//	os.Exit(0)
		//}
	}
	//logger.Error("Can't Connect to FS")
	//return c, errors.New("Can't Connect to FS")
}

func NwayFsInboundService(c *eventsocket.Connection) {

	//c.Send("events PLAIN CHANNEL_PROGRESS CHANNEL_PROGRESS_MEDIA TALK NOTALK CHANNEL_HANGUP_COMPLETE CHANNEL_CREATE CHANNEL_BRIDGE DTMF CHANNEL_DESTROY CHANNEL_HANGUP CHANNEL_BRIDGE CHANNEL_ANSWER CUSTOM sofia::register sofia::unregister da")
	c.Send("events PLAIN CHANNEL_ANSWER CHANNEL_HANGUP CHANNEL_HANGUP_COMPLETE CUSTOM dsr::recording")
	//go AutoCheckConnect(c)
	for {
		ev, err := c.ReadEvent()
		if err != nil {
			//这里加reconnect
			logger.Debug("error:---------------------------------------------", err)
			logger.Fatal(err)
			c.Close()
			c, err = Reconnect()
			if err != nil {
				logger.Error(err)
			} else {
				c.Send("events PLAIN ALL")
				logger.Info("Reconnected to FreeSwitch")
			}
		}
		if ev == nil {
			c.Close()
			c, err = Reconnect()
			if err != nil {
				logger.Error(err)
			} else {
				c.Send("events PLAIN ALL")
				logger.Info("Reconnected to FreeSwitch")
			}
			continue
		}
		//ev.PrettyPrint()
		nway_ev := *ev
		evt_name := ev.Get("Event-Name")
		//logger.Debug(evt_name)
		if evt_name == "CHANNEL_HANGUP" {
			//proc_hangup(c, ev)
			//可以在这里进行一个呼入队列寻找座席的动作，即呼入队列有在等待中的电话
			uuid := Nway_get_unique_uuid(&nway_ev)
			logger.Debug("a路挂机uuid：", uuid)

			nway_dsr_db.DelectRuntime(uuid)
		}
		if evt_name == "CHANNEL_HANGUP_COMPLETE" {
			proc_hangup_complete(c, &nway_ev)

			//可以在这里删除呼入队列
		}
		if evt_name == "DTMF" {
			//proc_dtmf(c, ev)
		}
		if evt_name == "CUSTOM" {
			logger.Debug("record file :%s", ev.Get("Dsr_Record_File"))
			go proc_custom(c, &nway_ev)
		}
		if evt_name == "CHANNEL_EXECUTE_COMPLETE" {
			//proc_execute_complete(c, ev)
		}
		if evt_name == "CHANNEL_PROGRESS_MEDIA" {
			//proc_progress_media(c, ev)
		}
		if evt_name == "CHANNEL_PROGRESS" {
			//proc_progress(c, ev)
		}

		if evt_name == "CHANNEL_CALLSTATE" {
			//proc_callstate(c, ev)
		}
		if evt_name == "CHANNEL_ANSWER" {
			//proc_answer(c, ev)
			//在这里更新接听的通道信息
			if Nway_get_direction(&nway_ev) == "outbound" {
				uuid := Nway_get_unique_uuid(&nway_ev)
				a_number, b_number := Nway_get_src_number(&nway_ev)
				logger.Debug("a路uuid打印：", uuid, "a:", a_number, "b:", b_number)
				logger.Debug("a路uuid打印：", uuid, "a:", a_number, "b:", b_number)
				nway_dsr_db.InsertDSRRuntime(uuid, a_number, b_number)
			}
		}
		if evt_name == "CHANNEL_DESTROY" {
			//proc_destroy(c, ev)
		}

		if evt_name == "CHANNEL_PARK" {
			//proc_park(c, ev)
		}
		if evt_name == "PLAYBACK_START" {
			//proc_playback_start(c, ev)
		}
		if evt_name == "PLAYBACK_STOP" {
			//proc_playback_stop(c, ev)
		}
		if evt_name == "CHANNEL_UNPARK" {
			//proc_unpark(c, ev)
		}
		if evt_name == "CHANNEL_HOLD" {
			//proc_hold(c, ev)
		}
		if evt_name == "CHANNEL_UNHOLD" {
			//proc_unhold(c, ev)
		}
		if evt_name == "CHANNEL_BRIDGE" {
			//proc_bridge(c, ev)
		}
		if evt_name == "CHANNEL_UNBRIDGE" {
			//proc_unbridge(c, ev)
		}
		if evt_name == "RECORD_START" {
			//proc_record_start(c, ev)
		}
		if evt_name == "RECORD_STOP" {
			//proc_record_stop(c, ev)
		}
		//logger.Debug(evt_name)
		if evt_name == "CHANNEL_ORIGINATE" {

			//proc_originate(c, ev)
		}
		if evt_name == "CHANNEL_CREATE" {
			//proc_create(c, ev)
		}
		if brunning == false {
			break
		}
	}
	c.Close()
	workResultLock.Done()
}
func nway_fs_api(conn *eventsocket.Connection, cmd string) (string, error) {
	if len(cmd) > 1 {
		var i int = 0
		for i < 5 {

			i = i + 1
			evt, err := conn.Send(cmd)
			if err != nil {
				//fmt.Println("nway_fs_api-----------------------------------------", err)
				logger.Error("execute command error:", err)
				conn.Close()
				conn, err = Reconnect()
				if err != nil {
					logger.Error("reconnect error:", err)
				} else {
					conn.Send("events PLAIN HEARTBEAT")
					logger.Info("reconnected")
				}
				continue
			} else {
				return evt.Body, nil
			}
		}

	} else {
		return "", errors.New("Command is Empty")
	}
	return "", errors.New("Send cmd to server failed!")
}

func Nway_uuid_hangup(uuid string) (string, error) {
	var cmd string

	cmd = "bgapi uuid_kill " + uuid
	logger.Info("挂断:", cmd)
	return nway_fs_api(global_c, cmd)
}
func Nway_get_unique_uuid(e *eventsocket.Event) string {
	src_uuid := e.Get("Caller-Unique-ID")
	if len(src_uuid) < 1 {
		src_uuid = e.Get("Caller-Unique-Id")
	}
	return src_uuid
}
func Nway_get_src_number(e *eventsocket.Event) (string, string) {
	tmpstr := e.Get("Caller-Caller-Id-Number")
	if len(tmpstr) < 1 {
		tmpstr = e.Get("Caller-Caller-ID-Number")
	}
	b_tmpstr := e.Get("Caller-Destination-Number")
	return tmpstr, b_tmpstr
}

func Nway_get_direction(e *eventsocket.Event) string {
	tmpstr := e.Get("Call-Direction")
	return tmpstr
}
func StartGlobalHealthService() error {
	defer func() {
		if err := recover(); err != nil {
			logger.Error("request to hw error:" + err.(string))

			return
		}
	}()
	global_c.Send("events PLAIN HEARTBEAT")
	//go AutoCheckConnect(c)
	for {
		ev, err := global_c.ReadEvent()
		if err != nil {
			//这里加reconnect
			logger.Debug("error:---------------------------------------------", err)
			logger.Fatal(err)
			global_c.Close()
			global_c, err = Reconnect()
			if err != nil {
				logger.Error(err)
			} else {
				global_c.Send("events PLAIN HEARTBEAT")
				logger.Info("Reconnected to FreeSwitch")
			}
		}
		if ev == nil {
			global_c.Close()
			global_c, err = Reconnect()
			if err != nil {
				logger.Error(err)
			} else {
				global_c.Send("events PLAIN HEARTBEAT")
				logger.Info("Reconnected to FreeSwitch")
			}
			continue
		}
	}

}
func StartInboundService() error {
	//Channels = channels
	//Channels = 30
	logger.Debug("*************************************************************************Channels:", Channels)

	defer func() {
		if err := recover(); err != nil {
			logger.Error("request to hw error:" + err.(string))

			return
		}
	}()
	conf_file := nway_path.GetCurrentDirectory() + "Nway.conf"
	iniconf, errc := config.NewConfig("ini", conf_file)
	//var result int64
	if errc != nil {
		//log.Fatal(errc)
		logger.Error("config file fatal,", errc)
		return errc
	}
	brunning = true
	logger.Info("Now to run Nway.com.cn FreeSWITCH interface service")
	ipstring := iniconf.String("fsip")
	auth := iniconf.String("auth")
	redisEvtDir := iniconf.String("event_direction")
	if redisEvtDir == "caller" {
		event_direction = true
	} else {
		event_direction = false
	}
	//outboundIpString := iniconf.String("fs-outbound-ip")
	logger.Info("The FreeSWITCH Ip:Port secrit ", ipstring, auth)
	//logger.Debug(ipstring)
	//logger.Debug(auth)

	//outboundIpString := iniconf.String("fs-outbound-ip")
	//err = StartOutboundService(outboundIpString)
	var c *eventsocket.Connection
	var err error
	for {
		c, err = eventsocket.Dial(ipstring, auth)
		if err != nil {
			logger.Error("Dial to FreeSWITCH Server Failed：", err)
			//logger.Debug("Dial to FreeSWITCH Server Failed：", err)
			time.Sleep(time.Duration(5) * time.Second)
			continue
		} else {
			break
		}

	}

	//用于全局处理远程请求的连接
	workResultLock.Add(1)
	global_c, err = eventsocket.Dial(ipstring, auth)
	if err != nil {
		logger.Error("Dial to FreeSWITCH Server Failed ", err)
		//logger.Debug("Dial to FreeSWITCH Server Failed ", err)
		c.Close()
		workResultLock.Done()
		os.Exit(0)
		return err
	}
	//Nway_get_uuid(global_c)
	logger.Info("Start a Inbound Service")
	go StartGlobalHealthService()
	go NwayFsInboundService(c)
	go nway_dsr_db.AutoCleanPGCdr()
	workResultLock.Wait()
	return nil

}
func StopInboundService() {
	brunning = false
	global_c.Close()
}
